<#assign object = doc.objects>
package ${object.package}.service;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.PrintWriter;

import java.sql.SQLException;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import redora.rdo.exceptions.*;
import redora.rdo.impl.*;
import redora.rdo.configuration.rdo.model.RedoraConfiguration;
import redora.rdo.configuration.rdo.service.RedoraConfigurationService;
import redora.rdo.configuration.rdo.model.base.RedoraConfigurationBase.Status;
import ${object.package}.service.base.*;

public class Upgrade extends ServiceBase {
	private Logger l = Logger.getLogger("${object.package}.model.service.Upgrade");

	public Upgrade() throws ConnectException {
		super();
	}
	
	private final static String SCRIPT_SOURCE_DIR = "src" + File.separator + "main" + File.separator + "resources" + File.separator + "upgrade";
	
	public void upgradeTable(PrintWriter out) throws ConnectException, PersistException, QueryException{
		l.log(Level.FINE, "start");
		List<String> modelList = new ArrayList<String>();
<#list object["/objects/object/name"] as modelname>
		modelList.add("${modelname}");
</#list>
		
		l.log(Level.INFO, "Found " + modelList.size() + " model files to process");
<#list object["/objects/object/name"] as modelname>
		${modelname?cap_first}TableUpdate ${modelname?lower_case}Update = new ${modelname?cap_first}TableUpdate();
		${modelname?lower_case}Update.create();
		${modelname?lower_case}Update.close();
</#list>
		
		l.log(Level.INFO, "Finished running create table scripts");
		executeUpgradeScript();
		
		connect();
		boolean retVal = false;
		try {
			rs = con.getMetaData().getTables(null, null, null, null);
			while(rs.next()){
				retVal = false;
				for(String tableName : modelList){
					if(rs.getString("TABLE_NAME").equalsIgnoreCase(tableName)){
						retVal = true;
					}
				}
				if(!retVal){
					l.log(Level.WARNING, "table " + rs.getString("TABLE_NAME") + " is not existed in xml file but it is in database");
					if(out != null)
						out.println("table " + rs.getString("TABLE_NAME") + " is not existed in xml file but it is in database." + "<br>");
				}
			}
		} catch (SQLException e) {
			l.log(Level.SEVERE, "Failed to open meta data", e);
			throw new QueryException("Failed to open meta data", e);
		}
		
	}
	
	public void check(PrintWriter out) throws ConnectException, QueryException {
		<#list object["/objects/object/name"] as modelname>
		${modelname?cap_first}TableUpdate ${modelname?lower_case}Update = new ${modelname?cap_first}TableUpdate();
		${modelname?lower_case}Update.check(out);
		${modelname?lower_case}Update.close(); 
		</#list>
	}
	
	public void executeUpgradeScript() throws ConnectException,
			PersistException {
		File dir = new File(SCRIPT_SOURCE_DIR);
		try{
			if (dir.exists()) {
				RedoraConfigurationService service = redora.rdo.configuration.rdo.service.ServiceFactory.redoraConfigurationService();
				File[] files = dir.listFiles(new FileFilter() {
					public boolean accept(File pathname) {
						return pathname.getName().endsWith(".sql");
					}
					
				});
				if (files == null)
					return;
				initDefaultScript();
				connect();
				s = con.createStatement();
				con.setAutoCommit(false);
				for (int i = 0; i < files.length; i++) {
					if (!files[i].isDirectory()) {
						List<String> sqlStr = loadSql(files[i].getPath());
						for (String sql : sqlStr) {
							s.addBatch(sql);
						}
					}
					RedoraConfiguration conf = new RedoraConfiguration();
					List<RedoraConfiguration> scriptList = service.findByScriptName(files[i].getName());
					if(scriptList != null && scriptList.size() > 0)
						conf = scriptList.get(0);
					conf.setScriptName(files[i].getName());
					conf.setStatus(Status.Ready);
					service.persist(conf);
				}
				s.executeBatch();
				con.commit();
				service.close();
			}
		}catch (Exception e) {
			l.log(Level.SEVERE, "Failed to execute UpgradeScript", e);
			throw new PersistException("Failed to execute UpgradeScript", e);
		}
	}
	
	public void executeUpgradeScript(String fileName) throws ConnectException,
			PersistException {
		File dir = new File(SCRIPT_SOURCE_DIR);
		if (dir.exists()) {
			File file = new File(SCRIPT_SOURCE_DIR + "/" + fileName);
			RedoraConfiguration conf = new RedoraConfiguration();
			if (file.exists()) {
				try {
					connect();
					s = con.createStatement();
					con.setAutoCommit(false);
					List<String> sqlStr = loadSql(file.getPath());
					for (String sql : sqlStr) {
						s.addBatch(sql);
					}
					s.executeBatch();
					con.commit();
					
					RedoraConfigurationService service = redora.rdo.configuration.rdo.service.ServiceFactory.redoraConfigurationService();
					List<RedoraConfiguration> scriptList = service.findByScriptName(fileName);
					if (scriptList != null && scriptList.size() > 0)
						conf = scriptList.get(0);
					conf.setScriptName(fileName);
					conf.setStatus(Status.Ready);
					service.persist(conf);
					service.close();
				} catch (Exception e) {
					l.log(Level.SEVERE, "Failed to execute UpgradeScript", e);
					throw new PersistException(
							"Failed to execute UpgradeScript", e);
				}
			}
		}
	}
	
	public void initDefaultScript() throws ConnectException,
			PersistException, QueryException, CopyException, BusinessRuleViolationException {
		File dir = new File(SCRIPT_SOURCE_DIR);
		if (dir.exists()) {
			File[] files = dir.listFiles(new FileFilter() {
					public boolean accept(File pathname) {
						return pathname.getName().endsWith(".sql");
					}
					
				});
			if (files != null) {
				RedoraConfigurationService service = redora.rdo.configuration.rdo.service.ServiceFactory.redoraConfigurationService();
				for (int i = 0; i < files.length; i++) {
					RedoraConfiguration conf = new RedoraConfiguration();
					conf.setScriptName(files[i].getName());
					conf.setStatus(Status.New);
					if (service.findByScriptName(files[i].getName()) == null || service.findByScriptName(files[i].getName()).size() < 1) {
						service.persist(conf);
					} 
				}
				service.close();
			}
		}
	}
	
	private List<String> loadSql(String sqlFile) throws Exception {
		List<String> sqlList = new ArrayList<String>();
		InputStream sqlFileIn = new FileInputStream(sqlFile);
		StringBuffer sqlSb = new StringBuffer();
		byte[] buff = new byte[1024];
		int byteRead = 0;
		while ((byteRead = sqlFileIn.read(buff)) != -1) {
			sqlSb.append(new String(buff, 0, byteRead));
		}
		String[] sqlArr = sqlSb.toString().split("(;\\s*\\r\\n)|(;\\s*\\n)");
		for (int i = 0; i < sqlArr.length; i++) {
			String sql = sqlArr[i].replaceAll("--.*", "").trim();
			if (!sql.equals("")) {
				sqlList.add(sql);
			}
		}
		return sqlList;
	}
	
	public static void main(String args[])throws ConnectException, PersistException, QueryException{
		Upgrade upgrade = new Upgrade();
		upgrade.upgradeTable(null);
		upgrade.check(null);
		upgrade.close();
	}
}
